/**********************************************/
/**			ll_rw_blk.c by doom119			  */
/**					June, 2010				  */
/**********************************************/
#include <blk.h>
#include <system.h>

struct request request[NR_REQUEST];
struct task* wait_for_request;

struct block_device blk_dev[NR_BLK_DEV] = { {0, 0}, };

static inline void lock_buffer(struct buffer_head * bh)
{
	cli();
	while(bh->lock)
		sleep_on(&bh->wait);
	bh->lock = 1;
	sti();
}

static void unlock_buffer(struct buffer_head * bh)
{
	if(!bh->lock)
		printk("ll_rw_blk unloc");
	bh->lock = 0;
	wake_up(&bh->wait);
}

static void add_request(struct block_device *dev, struct request * req)
{
	req->next = 0;
	cli();
	if(req->bh)
		req->bh->dirt = 0;
	if(!dev->current_request)
	{
		dev->current_request = req;
		sti();
		(dev->request_fn)();
		return;
	}
	//just for simple, not using lift algrith
	req->next = dev->current_request->next->next;
	dev->current_request->next = req;
	sti();
}

static void make_request(int major, int rw, struct buffer_head * bh)
{
	struct request * req;
	
	if(rw != READ && rw != WRITE)
		panic("make_request  1");

	lock_buffer(bh);
	if( (rw == WRITE && bh->dirt) || 
			(rw == READ && bh->uptodate) )
	{
		unlock_buffer(bh);
		return;
	}
repeat:
	if(rw == READ)
		req = request + NR_REQUEST;
	else
		req = request + NR_REQUEST * 2 / 3;

	while(--req > request)
	{
		if(req->dev < 0)
			break;
	}

	// this means no empty request slot
	if(req < request)
	{
		sleep_on(&wait_for_request);
		goto repeat;
	}

	req->dev = bh->dev;
	req->cmd = rw;
	req->errors = 0;
	req->start_sector = bh->blocknr<<1;
	req->nr_sectors = 2;
	req->buffer = bh->data;
	req->wait = 0;
	req->bh = bh;
	req->next = 0;
	add_request(major + blk_dev, req);
}

void ll_rw_block(int rw, struct buffer_head * bh)
{
	unsigned int major;

	if( (major = MAJOR(bh->dev)) >= NR_BLK_DEV ||
			!(blk_dev[major].request_fn) )
	{
		printk("ll_rw_block    ");
		return;
	}
	make_request(major, rw, bh);
}

void blk_dev_init(void)
{
	int i;
	for(i = 0; i < NR_REQUEST; ++i)
	{
		request[i].dev = -1;
		request[i].next = 0;
	}
	printk("blk_dev_init OK");
}
